// Copyright 2018 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Scrape `performance_schema.file_summary_by_event_name`.

package collector

import (
	"context"
	"database/sql"

	"github.com/go-kit/kit/log"
	"github.com/prometheus/client_golang/prometheus"
)

//采集长事务sql
const performanceSchemaThread = `
SELECT 'long_transaction' as long_transaction,
count(*)
FROM
performance_schema.threads a
INNER JOIN
  (SELECT
	thread_id,
	GROUP_CONCAT(
	  CASE
		WHEN EVENT_NAME = 'statement/sql/begin'
		THEN "transaction_begin"
		ELSE sql_text
	  END
	  ORDER BY event_id SEPARATOR ";"
	) AS sql_text
  FROM
	performance_schema.events_statements_history
  WHERE (
	  sql_text NOT LIKE '%INFORMATION_SCHEMA%'
	  AND sql_text NOT LIKE '%performance_schema%'
	)
  GROUP BY thread_id) AS t2
  ON a.THREAD_ID = t2.thread_id
INNER JOIN INFORMATION_SCHEMA.PROCESSLIST AS t3
  ON t3.ID = a.PROCESSLIST_ID
INNER JOIN INFORMATION_SCHEMA.innodb_trx AS t4
  ON a.PROCESSLIST_ID = t4.trx_mysql_thread_id
WHERE a.CONNECTION_TYPE NOT IN ('CONNECTION_TYPE', 'Plugin')
AND a.CONNECTION_TYPE IS NOT NULL
AND (
  UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(t4.trx_started) > 5
);
	`

// Metric descriptors.
var (
	performanceSchemaLongTransactionDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, performanceSchema, "transaction_long_total"),
		"The total long transaction  query > 5",
		[]string{"event_name", "mode"}, nil,
	)
)

// ScrapePerfFileEvents collects from `performance_schema.file_summary_by_event_name`.
type ScrapePerfLongtransEvents struct{}

// Name of the Scraper. Should be unique.
func (ScrapePerfLongtransEvents) Name() string {
	return "perf_schema.longtransactionEvents"
}

// Help describes the role of the Scraper.
func (ScrapePerfLongtransEvents) Help() string {
	return "Collect metrics from performance_schema.threads  query>5"
}

// Version of MySQL from which scraper is available.
func (ScrapePerfLongtransEvents) Version() float64 {
	return 5.6
}

// Scrape collects data from database connection and sends it over channel as prometheus metric.
func (ScrapePerfLongtransEvents) Scrape(ctx context.Context, db *sql.DB, ch chan<- prometheus.Metric, logger log.Logger) error {
	// Timers here are returned in picoseconds.
	perfSchemaLongTransactionRow, err := db.QueryContext(ctx, performanceSchemaThread)
	if err != nil {
		return err
	}
	defer perfSchemaLongTransactionRow.Close()

	var (
		long_transaction string
		total            uint64
	)
	for perfSchemaLongTransactionRow.Next() {
		if err := perfSchemaLongTransactionRow.Scan(
			&long_transaction,
			&total,
		); err != nil {
			return err
		}
		ch <- prometheus.MustNewConstMetric(
			performanceSchemaLongTransactionDesc, prometheus.GaugeValue, float64(total),
			long_transaction, "query",
		)
	}
	return nil
}

// check interface
var _ Scraper = ScrapePerfFileEvents{}
